package edu.unipd.p2t.db;

import java.security.MessageDigest;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;

import edu.unipd.p2t.connection.ConnectionManager;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public class DataManager {
	private static DataManager instance = null;
	private SQLiteDatabaseAdapter aSQLiteDatabaseAdapter;
	private SQLiteDatabase myDB;
	private final String MY_DATABASE_NAME = "peer2tweet"; 
    private final String MY_DATABASE_TABLE = "messages"; 
	private static final String TAG = "DataManager";  
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	/**
	 * Costruttore privato per permettere la costruzione tramite singleton
	 * @param context C
	 */
	private DataManager(Context context){
		aSQLiteDatabaseAdapter=SQLiteDatabaseAdapter.getInstance(context,MY_DATABASE_NAME);
		// connessione
		myDB = null;
		try{   
			// recupero il DB
			myDB = aSQLiteDatabaseAdapter.getDatabase();

		}catch(SQLException e){
			Log.e(TAG,"SQLEccezione : ",e);
		}catch(Exception e){
			Log.e(TAG,"Eccezione : ",e);
		}
	}

	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		super.finalize();
		myDB.close();
	}
	
	/**
	 * Implementazione del pattern singleton
	 * @param context Contesto di esecuzione dell'applicazione
	 * @return istanza singleton del DBInstance
	 */
	public static DataManager getInstance(Context context) {
		if(instance==null)
			instance=new DataManager(context);
		return instance;
	}
	
	/**
	 * Estrae gli hash univoci di tutti i messaggi presenti in database
	 * @return Un array di stringhe contenente tutti gli hash
	 */
	public String[] getHash(){
		String[] columns=new String[1];
        columns[0]=new String("hash");
        
        
        Cursor c=myDB.query(true,MY_DATABASE_TABLE, columns, null, null, null, null, null, null);
        String[] hash=new String[c.getCount()];
        for(int i=0;i<c.getCount();i=i+1)
        {
         	c.moveToPosition(i);
         	hash[i]=c.getString(c.getColumnIndex("hash"));
         	Log.i(TAG,"dati: "+hash[i]);
        }
        
        return hash; 
     }
	
	/**
	 * Estrae il messaggio con un determinato hash
	 * @param hash hash che identifica il messaggio
	 * @return oggetto Message che rappresenta un messaggio
	 */
	public Message getMessage(String hash){
		String[] columns=new String[4];
        columns[0]=new String("date");
        columns[1]=new String("author");
        columns[2]=new String("message");
        columns[3]=new String("hop");

        Cursor c=myDB.query(MY_DATABASE_TABLE, columns, "hash='"+hash+"'", null, null, null, null);

        c.moveToPosition(0);
        String date=c.getString(c.getColumnIndex("date"));
        String author=c.getString(c.getColumnIndex("author"));
        String message=c.getString(c.getColumnIndex("message"));
        int hop=c.getInt(c.getColumnIndex("hop"));
        
        Message m=null;
		try {
			m = new Message(author,message, sdf.parse(date), hop );
		} catch (ParseException e) {
			Log.i(TAG,"Errore nel parsing della data");
		}
        
        return m;  
	}
	
	/**
	 * Estrae i messaggi che hanno un certo hash
	 * @param hash hash che identifica il messaggio
	 * @return oggetto Message che rappresenta un messaggio
	 */
	public Message[] getMessages(String[] hash){
		Message[] m=new Message[hash.length];
        
		for(int i=0;i<hash.length;i++)
			m[i]=getMessage(hash[i]);
		
        return m;  
	}
	
	/**
	 * Estrae tutti i messaggi dal database ordinandoli per data Decrescente
	 * @return Array di messaggi
	 */
	public Message[] getMessages(){
		String[] columns=new String[5];
        columns[0]=new String("date");
        columns[1]=new String("author");
        columns[2]=new String("message");
        columns[3]=new String("hop");
        columns[4]=new String("hash");
        
        Cursor c=myDB.query(MY_DATABASE_TABLE, columns, null, null, null, null, "date DESC");
        Message[] m=new Message[c.getCount()];
        for(int i=0;i<c.getCount();i++)
		{
	        c.moveToPosition(i);
	        String date=c.getString(c.getColumnIndex("date"));
	        String author=c.getString(c.getColumnIndex("author"));
	        String message=c.getString(c.getColumnIndex("message"));
	        int hop=c.getInt(c.getColumnIndex("hop"));
	        String hash=c.getString(c.getColumnIndex("hash"));
			
	        
	        try {
				m[i] = new Message(author,message, sdf.parse(date), hop );
			} catch (ParseException e) {
				Log.i(TAG,"Errore nel parsing della data");
			}
		}
        
        return m;
	}
	
	
	/**
	 * Funzione che inserisce un messaggio nel database
	 * @param m Messaggio da inserire
	 */
	public void insMessage(Message m){
		myDB.execSQL("INSERT INTO " + MY_DATABASE_TABLE 
			        + " (date, author, message, hop, hash)" 
			        + " VALUES ('" + sdf.format(m.getDate())
			        + "', '"+ m.getAuthor()
			        + "', '"+ m.getText()
			        + "',"+ Integer.toString(m.getHops_to_live())
			        + ", '"+m.getHash()
			        + "');"); 
	}
	
	/**
	 * Funzione di utilità che genera il message digest del testo in input utilizzando l'algoritmo MD5
	 * @param msg testo in input
	 * @return messagge digest dell'input
	 */
	/**public static String MD5(String msg) {
		StringBuffer hexString=new StringBuffer();
		try{ 
			MessageDigest algorithm = MessageDigest.getInstance("MD5");
	      	algorithm.reset();
	      	algorithm.update(msg.getBytes());
	      	byte messageDigest[] = algorithm.digest();
	                  
	      	Log.i(TAG,"lenght: "+Integer.toString(messageDigest.length));
	      	for (int i=0;i<messageDigest.length;i++) {
	      		hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
	      	}
	      	Log.i(TAG,"MD5: "+hexString.toString());

		}catch(Exception e){
			Log.e(TAG,"Eccezione MD5: ",e);
        }
		
		return hexString.toString();
	}*/
	
	/**
	 * Funzione di utilità che restituisce la data/ora corrente nel formato ISO 8601, ovvero anno-mese-giorno ora-minuti-secondi
	 * @return stringa della data/ora corrente in formato ISO 8601
	 */
	public static String dataoraCorrente(){
		GregorianCalendar gc = new GregorianCalendar();
		
		return sdf.format(gc.getTime());
	}
	
}
